# 实现目标2，方案二 XGBoost SVC
# 最终采用

import pandas as pd
from sklearn.model_selection import train_test_split, GridSearchCV, cross_val_score
from sklearn.svm import SVC
from xgboost import XGBClassifier
from sklearn.ensemble import VotingClassifier
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score, confusion_matrix, ConfusionMatrixDisplay, classification_report
import matplotlib.pyplot as plt
import numpy as np

# 设置中文字体支持
plt.rcParams['font.family'] = 'SimHei'
plt.rcParams['axes.unicode_minus'] = False

# 加载数据
df = pd.read_csv('no_neg_DBSCAN_smote_g2.csv')

# 分离特征和标签
X = df[['Temperature', 'Humidity', 'PM2.5', 'PM10', 'NO2', 'SO2', 'CO', 'Proximity_to_Industrial_Areas', 'Population_Density']]
y = df['Air Quality']

# 将分类标签转换为数值
y_numeric = pd.Categorical(y).codes

# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y_numeric, test_size=0.2, random_state=42)

# 定义各个模型
svm = SVC(probability=True)
xgb = XGBClassifier()

# 使用VotingClassifier进行模型集成
voting_clf = VotingClassifier(estimators=[
    ('svc', svm), 
    ('xgbclassifier', xgb)],
    voting='soft'
)

# 定义每个分类器的参数网格
param_grids = {
    'svc': {
        'svc__C': range(388, 393),
        'svc__gamma': [0.0008, 0.0009, 0.001]
    },
    'xgbclassifier': {
        'xgbclassifier__n_estimators': range(267, 275),
        'xgbclassifier__max_depth': [6, 7, 8]
    }
}


# 合并所有分类器的参数网格
param_grid = {key: value for est in voting_clf.estimators for key, value in param_grids[est[0]].items()}

# 初始化GridSearchCV，使用F1宏平均作为评分标准
grid_search = GridSearchCV(estimator=voting_clf, param_grid=param_grid, cv=5, scoring='f1_macro', n_jobs=-1)

# 执行参数搜索
grid_search.fit(X_train, y_train)

# 输出最佳参数和对应的最佳得分
print("Best parameters found: ", grid_search.best_params_)
print("Best F1 score: ", grid_search.best_score_)

# 使用最佳参数评估测试集
best_voting_clf = grid_search.best_estimator_
y_pred_best = best_voting_clf.predict(X_test)

# 计算并打印测试集上的性能指标
accuracy_best = accuracy_score(y_test, y_pred_best)
precision_best = precision_score(y_test, y_pred_best, average='macro')
recall_best = recall_score(y_test, y_pred_best, average='macro')
f1_best = f1_score(y_test, y_pred_best, average='macro')

print(f"Best模型 - 准确率: {accuracy_best}")
print(f"Best模型 - 精确率: {precision_best}")
print(f"Best模型 - 召回率: {recall_best}")
print(f"Best模型 - F1分数: {f1_best}")

# 绘制混淆矩阵
conf_mat = confusion_matrix(y_test, y_pred_best)
disp = ConfusionMatrixDisplay(confusion_matrix=conf_mat, display_labels=np.unique(y_numeric))
disp.plot()
plt.title("混淆矩阵")
plt.show()

# 创建从数字标签到类别名称的映射
label_names = df['Air Quality'].astype('category').cat.categories.tolist()
label_to_name = dict(enumerate(label_names))

# 确保y_test和y_pred_best都是基于原始的类别名称
y_test_names = pd.Series(y_test).map(label_to_name)
y_pred_names = pd.Series(y_pred_best).map(label_to_name)

# 打印分类报告
report = classification_report(y_test_names, y_pred_names, target_names=label_names, zero_division=0)
print("分类报告:\n", report)

# 打印每一类的详细信息
report_dict = classification_report(y_test_names, y_pred_names, output_dict=True, target_names=label_names, zero_division=0)
for label in label_names:
    metrics = report_dict[label]
    print(f"对于类别 {label}:")
    print(f"  精确率: {metrics['precision']}")
    print(f"  召回率: {metrics['recall']}")
    print(f"  F1分数: {metrics['f1-score']}")
    print(f"  支持度: {metrics['support']}")